package com.qiangqiang.resoldhouse.redis;

import com.qiangqiang.resoldhouse.util.JsonUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.Transaction;

import java.util.List;
import java.util.UUID;


@Service
public class RedisService {

    @Autowired
    JedisPool jedisPool;

    /**
     * 设置对象
     */
    public <T> boolean set(KeyPrefix prefix, String key, T value) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            String str = JsonUtil.beanToString(value);
            if (str == null || str.length() <= 0) {
                return false;
            }
            //生成真正的key
            String realKey = prefix.getPrefix() + key;
            int seconds = prefix.expireSecond();
            if (seconds <= 0) {
                jedis.set(realKey, str);
            } else {
                //可以设置过期时间
                jedis.setex(realKey, seconds, str);
            }
            return true;
        } finally {
            returnToPool(jedis);
        }
    }

    /**
     * 获取当个对象
     */
    public <T> T get(KeyPrefix prefix, String key, Class<T> clazz) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            //生成真正的key
            String realKey = prefix.getPrefix() + key;
            String str = jedis.get(realKey);
            T t = JsonUtil.stringTobean(str, clazz);
            return t;
        } finally {
            returnToPool(jedis);
        }
    }

    /**
     * @param [prefix, key, acquireTimeout]
     *                 prefix : 前缀
     *                 acquireTimeout：轮询时间
     * @return boolean
     * @author sky
     * @date 2018/7/10
     * @describe: redis 分布式锁，锁方法
     */
    public String tryLock(KeyPrefix prefix, String key, long acquireTimeout) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            String identifier = UUID.randomUUID().toString();
            String realKey = prefix.getPrefix() + key;
            //获取锁的超时时间，超过这个时间则放弃获取锁
            long end = System.currentTimeMillis() + acquireTimeout;
            while (System.currentTimeMillis() < end) {
                if (jedis.setnx(realKey, identifier) == 1) {
                    //设置超时时间
                    jedis.expire(realKey, prefix.expireSecond());
                    return identifier;
                }
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        } finally {
            returnToPool(jedis);
        }
        return null;
    }

    /**
     * @param [prefix, key, identifier]
     *                 identifier : 释放锁的标志
     * @return boolean
     * @author sky
     * @date 2018/7/10
     * @describe: 释放锁
     */
    public boolean releaseLock(KeyPrefix prefix, String key, String identifier) {
        Jedis jedis = null;
        boolean retFlag = false;
        try {
            jedis = jedisPool.getResource();
            String realKey = prefix.getPrefix() + key;
            while (true) {
                //监控 realKey, 准备开启事务
                jedis.watch(realKey);
                if (identifier.equals(jedis.get(realKey))) {
                    Transaction transaction = jedis.multi();
                    transaction.del(realKey);
                    //提交事务
                    List<Object> results = transaction.exec();
                    System.out.println(results);
                    //是否提交成功
                    if (results == null) {
                        continue;
                    }
                    retFlag = true;
                }
                jedis.unwatch();
                break;
            }
        } finally {
            returnToPool(jedis);
        }
        return retFlag;
    }

    /**
      * @author sky
      * @date 2018/7/12
      * @param [taskId]
      * @return boolean
      * @describe:
      * 该任务是否被领取
     */
    public boolean isReceived(String taskId){
        return get(TaskPrefix.taskIdPrefix,taskId,String.class)==null;
    }

    private void returnToPool(Jedis jedis) {
        if (jedis != null) {
            jedis.close();
        }
    }

}
